package com.one.group.admin.excel;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.util.ListUtils;
import com.one.group.admin.mapper.ParkingSpaceMapper;
import com.one.group.enums.ResultEnum;
import com.one.group.exception.BusinessException;
import com.one.group.model.entity.ParkingSpace;
import com.one.group.service.ParkingSpaceService;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 车位数据读取监听器
 */
@Slf4j
public class ParkingSpaceDataReadListener implements ReadListener<ParkingSpaceData> {

    /**
     * 每隔100条存储数据库，实际使用中可以100条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 100;

    /**
     * 缓存的数据
     */
    private List<ParkingSpaceData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    private ParkingSpaceService parkingSpaceService;
    private ParkingSpaceMapper parkingSpaceMapper;
    private Long tenantId;

    // 小区名称到ID的映射缓存
    private Map<String, Long> cellNameToIdMap = new HashMap<>();

    // 车位类型映射
    private static final Map<String, Integer> TYPE_MAP = new HashMap<>();
    static {
        TYPE_MAP.put("产权车位", 1);
        TYPE_MAP.put("公共车位", 2);
        TYPE_MAP.put("租赁车位", 3);
        TYPE_MAP.put("访客车位", 4);
        TYPE_MAP.put("其他", 5);
    }

    // 车位状态映射
    private static final Map<String, Integer> STATUS_MAP = new HashMap<>();
    static {
        STATUS_MAP.put("空置", 1);
        STATUS_MAP.put("自用", 2);
        STATUS_MAP.put("出租", 3);
        STATUS_MAP.put("出售", 4);
        STATUS_MAP.put("占用", 5);
        STATUS_MAP.put("报废", 6);
    }

    public ParkingSpaceDataReadListener() {
    }

    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     * @param parkingSpaceService 车位服务
     * @param parkingSpaceMapper 车位Mapper
     * @param tenantId 租户ID
     */
    public ParkingSpaceDataReadListener(ParkingSpaceService parkingSpaceService, ParkingSpaceMapper parkingSpaceMapper, Long tenantId) {
        this.parkingSpaceService = parkingSpaceService;
        this.parkingSpaceMapper = parkingSpaceMapper;
        this.tenantId = tenantId;
        
        // 初始化时加载所有小区映射
        initCellNameMapping();
    }

    /**
     * 初始化小区名称到ID的映射
     */
    private void initCellNameMapping() {
        try {
            List<Map<String, Object>> cellList = parkingSpaceMapper.getAllCellsByTenantId(tenantId);
            for (Map<String, Object> cell : cellList) {
                String cellName = (String) cell.get("name");
                Long cellId = ((Number) cell.get("id")).longValue();
                cellNameToIdMap.put(cellName, cellId);
            }
        } catch (Exception e) {
            throw new RuntimeException("加载小区映射失败: " + e.getMessage());
        }
    }

    /**
     * 这个每一条数据解析都会来调用
     * @param data 一行数据
     * @param context 分析上下文
     */
    @Override
    public void invoke(ParkingSpaceData data, AnalysisContext context) {
//        log.info("解析到一条数据:{}", data);
        cachedDataList.add(data);
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     * @param context 分析上下文
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        saveData();
//        log.info("所有数据解析完成！");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
//        log.info("{}条数据，开始存储数据库！", cachedDataList.size());

        List<ParkingSpace> parkingSpaceList = cachedDataList.stream()
                .filter(data -> !StrUtil.isEmpty(data.getSpaceNo()))
                .map(data -> {
                    try {
                        // 从缓存中获取小区ID
                        Long cellId = cellNameToIdMap.get(data.getCellName());
                        if (cellId == null) {
                            throw new BusinessException(ResultEnum.DATA_NOT_EXIST.getCode(),
                                String.format("车位编号[%s]的小区名称[%s]不存在!",
                                    data.getSpaceNo(), data.getCellName()));
                        }

                        // 根据类型名称获取类型ID
                        Integer type = TYPE_MAP.get(data.getTypeName());
                        if (type == null) {
                            throw new BusinessException(ResultEnum.DATA_NOT_EXIST.getCode(),
                                String.format("车位编号[%s]的车位类型[%s]不存在!",
                                    data.getSpaceNo(), data.getTypeName()));
                        }

                        // 根据状态名称获取状态ID
                        Integer status = STATUS_MAP.get(data.getStatusName());
                        if (status == null) {
                            throw new BusinessException(ResultEnum.DATA_NOT_EXIST.getCode(),
                                String.format("车位编号[%s]的车位状态[%s]不存在!",
                                    data.getSpaceNo(), data.getStatusName()));
                        }

                        ParkingSpace parkingSpace = new ParkingSpace();
                        parkingSpace.setSpaceNo(data.getSpaceNo());
                        parkingSpace.setCellId(cellId);
                        parkingSpace.setType(type);
                        parkingSpace.setStatus(status);
                        parkingSpace.setArea(data.getArea());
                        parkingSpace.setLocation(data.getLocation());
                        parkingSpace.setRemark(data.getRemark());
                        parkingSpace.setCreatedTime(new Date());
                        parkingSpace.setUpdatedTime(new Date());
                        parkingSpace.setTenantId(tenantId);
                        return parkingSpace;
                    } catch (Exception e) {
                        throw new BusinessException(ResultEnum.DATA_PROCESS_ERROR.getCode(),
                            String.format("车位编号[%s]数据处理失败：%s，请检查数据格式是否正确",
                                data.getSpaceNo(), e.getMessage()));
                    }
                }).collect(Collectors.toList());
        
        // 保存到数据库
        try {
            parkingSpaceService.saveBatch(parkingSpaceList);
        } catch (Exception e) {
            throw new BusinessException(ResultEnum.IMPORT_FAIL.getCode(), "批量保存车位数据失败!");
        }

//        log.info("存储数据库成功！");
    }
}
